package cn.weiyan.dtx.txmsgdemo.bank1.server.impl;

import cn.weiyan.dtx.txmsgdemo.bank1.dao.AccountInfoDao;
import cn.weiyan.dtx.txmsgdemo.bank1.model.AccountChangeEvent;
import cn.weiyan.dtx.txmsgdemo.bank1.server.AccountInfoService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * @author misterWei
 * @create 2020年02月16号:12点25分
 * @mailbox mynameisweiyan@gmail.com
 */
@Service
@Slf4j
public class AccountInfoServiceImpl implements AccountInfoService {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private AccountInfoDao accountInfoDao;

    /**
     * 该方法是 controller 层调用 不执行实际数据操作,而是采用发送消息的方式
     * @param accountChangeEvent
     */
    @Override
    public void sendUpdateAccountBalance(AccountChangeEvent accountChangeEvent) {
        log.info("开始发送消息，事务号：{}",accountChangeEvent.getTxNo());


        //构建消息体,发送消息
        String message = JSON.toJSONString(accountChangeEvent);

        //sendMessageInTransaction() 使用该方法用来后续的事务监听.
        Message<String> stringMessage = MessageBuilder.withPayload(message).build();
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction("producer_txmsg_bank1", "topic_txmsg", stringMessage, null);

        //该事务消息状态
        log.info(transactionSendResult.getLocalTransactionState().toString());

    }

    /**
     * 该方法为具体的数据库实例操作.
     * @param accountChangeEvent
     */

    @Override
    @Transactional
    public void doUpdateAccountBalance(AccountChangeEvent accountChangeEvent) {
        log.info("开始更新本地事务，事务号：{}",accountChangeEvent.getTxNo());

        //执行本地事务
      accountInfoDao.updateAccountBalance(accountChangeEvent.getAccountNo(),accountChangeEvent.getAmount() * -1);

      //添加tx事务号,做幂等性操作.
        accountInfoDao.addTx(accountChangeEvent.getTxNo());
        if(accountChangeEvent.getAmount() == 2){
            throw new RuntimeException("bank1更新本地事务时抛出异常");
        }
        log.info("结束更新本地事务，事务号：{}",accountChangeEvent.getTxNo());


        if (accountChangeEvent.getAmount() == 3) {
            throw new RuntimeException("bank2 制造异常...");
        }
    }
}
